/**
 * #info
 *
 *@author   wuwg
 *@createTime   2018/03/20
 *@updateTime   2018/04/18
 *@description  transfer  component  穿梭框组件
 */

/**
 * #item
 *
 * @type        aty-transfer
 * @cn          穿梭框
 * @menu        表单
 * @stPlugin    true
 * @stContainer false
 * @children   [aty-icon,aty-text,aty-link,aty-panel,aty-button]
 */
/**
 * #extendproperty
 *
 * @name    slot
 * @cn      slot插槽
 * @options [default,left-footer,right-footer]
 * @type    list
 * @description  [default, left-footer, right-footer], default插槽，用于默认插入一些内容，插入之后左右面板都会有
 * left-footer插槽，用于默认插入左侧的内容
 * right-footer插槽，用于默认插入右侧内容
 */
import config from '../../../config/config.js'

// components
import List from './list/index.vue'
// mixins
import Locale from '../../../mixins/locale.js'
// prefix
const prefixCls = config.prefix + '-transfer'
// module
export default {
  name: config.prefix + '-transfer',
  mixins: [Locale],
  render (h) {
    function cloneVNode (vnode) {
      const clonedChildren = vnode.children && vnode.children.map(vnode => cloneVNode(vnode))
      const cloned = h(vnode.tag, vnode.data, clonedChildren)
      cloned.text = vnode.text
      cloned.isComment = vnode.isComment
      cloned.componentOptions = vnode.componentOptions
      cloned.elm = vnode.elm
      cloned.context = vnode.context
      cloned.ns = vnode.ns
      cloned.isStatic = vnode.isStatic
      cloned.key = vnode.key
      return cloned
    }
    const vNodes = this.$slots.default ? this.$slots.default : (this.$slots['left-footer'] === undefined ? [] : this.$slots['left-footer'])
    const clonedVNodes = this.$slots.default ? vNodes.map(vnode => cloneVNode(vnode)) : (this.$slots['right-footer'] === undefined ? [] : this.$slots['right-footer'])
    return (
      <div class={this.classes}>
        <List ref={'left'}
          prefixCls={this.prefixCls + '-list'}
          data={this.leftData}
          renderFormat={this.renderFormat}
          checkedKeys={this.leftCheckedKeys}
          validKeysCount={this.leftValidKeysCount}
          listStyle={this.listStyle}
          title={this.localeTitles[0]}
          filterable={this.filterable}
          filterPlaceholder={this.localeFilterPlaceholder}
          filterMethod={this.filterMethod}
          notFoundText={this.localeNotFoundText}
          on-checked-keys-change={this.handleLeftCheckedKeysChange}
          >{vNodes}</List>
          <div class={this.prefixCls + '-operation'}>
            <button type={'button'} disabled={!this.rightValidKeysCount > 0} on-click={() => {this.moveTo('left')}} class={this.prefixCls + '-operation-btn' + ' aty-btn aty-btn-primary'}>
              <i class={'aty-icon aty-icon-ios-arrow-left'}></i>&nbsp;{ this.operations[0] }
            </button>
            <button type={'button'} disabled={!this.leftValidKeysCount > 0} on-click={() => {this.moveTo('right')}} class={this.prefixCls + '-operation-btn' + ' aty-btn aty-btn-primary'}>
              { this.operations[1] }&nbsp;<i class={'aty-icon aty-icon-ios-arrow-right'}></i>
            </button>
          </div>
          <List
          ref={'right'}
          prefixCls={this.prefixCls + '-list'}
          data={this.rightData}
          renderFormat={this.renderFormat}
          checkedKeys={this.rightCheckedKeys}
          validKeysCount={this.rightValidKeysCount}
          listStyle={this.listStyle}
          title={this.localeTitles[0]}
          filterable={this.filterable}
          filterPlaceholder={this.localeFilterPlaceholder}
          filterMethod={this.filterMethod}
          notFoundText={this.localeNotFoundText}
          on-checked-keys-change={this.handleRightCheckedKeysChange}
          >
          {clonedVNodes}
          </List>
      </div>
    )
  },
  props: {
    /**
     * #property
     *
     * @name     name
     * @cn      属性名称
     * @group   基本属性
     * @type    string
     * @description 值对应的属性名
     */
    name: {
      type: String
    },
    /**
     * #property
     *
     * @name     data
     * @cn      所有数据
     * @group   数据
     * @type    array
     * @bind    must
     * @description 数据源，其中的数据将会被渲染到左边一栏中，targetKeys中指定的除外。
     */
    data: {
      type: Array,
      default () {
        return []
      }
    },
    /**
     * #property
     *
     * @name     renderFormat
     * @cn      渲染函数
     * @group   基本属性
     * @type    function
     * @bind    must
     * @value   item.name || item.code
     * @description 每行数据渲染函数，该函数的入参为 data 中的项
     */
    renderFormat: {
      type: Function,
      default (item) {
        return item.name || item.code
      }
    },
    /**
     * #property
     *
     * @name     targetKeys
     * @cn      显示在右侧框数据的key集合
     * @group   数据
     * @type    array
     * @bind    must
     * @description 显示在右侧框数据的key集合，数组
     */
    targetKeys: {
      type: Array,
      default () {
        return []
      }
    },
    /**
     * #property
     *
     * @name     selectedKeys
     * @cn      设置哪些项应该被选中
     * @group   数据
     * @type    array
     * @bind    must
     * @description 设置哪些项应该被选中，数组
     */
    selectedKeys: {
      type: Array,
      default () {
        return []
      }
    },
    /**
     * #property
     *
     * @name     listStyle
     * @cn      两个穿梭框的自定义样式
     * @group   基本属性
     * @type    object
     * @bind    must
     * @description 两个穿梭框的自定义样式
     */
    listStyle: {
      type: Object,
      default () {
        return {}
      }
    },
    /**
     * #property
     *
     * @name     titles
     * @cn      标题集合
     * @group   数据
     * @type    array
     * @bind    must
     * @description 标题集合 【左侧标题，右侧标题】
     */
    titles: {
      type: Array
    },

    /**
     * #property
     *
     * @name     operations
     * @cn        操作文案集合，顺序从上至下
     * @group   数据
     * @type    array
     * @bind    must
     * @description 操作文案集合 【向左移动，向右移动】
     */
    operations: {
      type: Array,
      default () {
        return []
      }
    },
    /**
     * #property
     *
     * @name   filterable
     * @cn     是否显示搜索框
     * @group   控制
     * @type    boolean
     * @value  false
     * @description 是否显示搜索框
     */
    filterable: {
      type: Boolean,
      default: false
    },
    /**
     * #property
     *
     * @name     filterPlaceholder
     * @cn       搜索框的占位
     * @group   基本属性
     * @type    string
     * @description 搜索框的占位
     */
    filterPlaceholder: {
      type: String
    },
    /**
     * #property
     *
     * @name     filterMethod
     * @cn       自定义搜索函数
     * @group   基本属性
     * @type    function
     * @bind    must
     * @description 自定义搜索函数，入参为 data 和 query，data 为项，query 为当前输入的搜索词
     */
    filterMethod: {
      type: Function,
      default (data, query) {
        const type = ('name' in data) ? 'name' : 'code'
        return data[type].indexOf(query) > -1
      }
    },
    /**
     * #property
     *
     * @name     notFoundText
     * @cn       当列表为空时显示的内容
     * @group   基本属性
     * @type    string
     * @description 当列表为空时显示的内容
     */
    notFoundText: {
      type: String
    }
  },
  data () {
    return {
      prefixCls: prefixCls,
      leftData: [],
      rightData: [],
      leftCheckedKeys: [],
      rightCheckedKeys: []
    }
  },
  watch: {
    // 显示在右侧框数据的key集合
    targetKeys () {
      this.splitData(false)
    },
    // 数据源，其中的数据将会被渲染到左边一栏中，targetKeys 中指定的除外。
    data () {
      this.splitData(false)
    }
  },
  computed: {
    classes () {
      return [`${prefixCls}`]
    },
    leftValidKeysCount () {
      return this.getValidKeys('left').length
    },
    rightValidKeysCount () {
      return this.getValidKeys('right').length
    },
    localeFilterPlaceholder () {
      if (this.filterPlaceholder === undefined) {
        return this.t('i.transfer.filterPlaceholder')
      } else {
        return this.filterPlaceholder
      }
    },
    localeNotFoundText () {
      if (this.notFoundText === undefined) {
        return this.t('i.transfer.notFoundText')
      } else {
        return this.notFoundText
      }
    },
    localeTitles () {
      if (this.titles === undefined) {
        return [this.t('i.transfer.titles.source'), this.t('i.transfer.titles.target')]
      } else {
        return this.titles
      }
    }
  },
  methods: {
    getValidKeys (direction) {
      return this[`${direction}Data`]
        .filter(data => !data.disabled && this[`${direction}CheckedKeys`].indexOf(data.code) > -1)
        .map(data => data.code)
    },
    splitData (init = false) {
      this.leftData = [...this.data]
      this.rightData = []
      if (this.targetKeys.length > 0) {
        this.targetKeys.forEach((targetKey) => {
          const filteredData = this.leftData.filter((data, index) => {
            if (data.code === targetKey) {
              this.leftData.splice(index, 1)
              return true
            } else {
              return false
            }
          })
          if (filteredData && filteredData.length > 0) {
            this.rightData.push(filteredData[0])
          }
        })
      }
      // 如果是初始化
      if (init) {
        this.$nextTick(() => {
          this.splitSelectedKey()
        })
      }
    },
    splitSelectedKey () {
      const selectedKeys = this.selectedKeys
      if (selectedKeys.length > 0) {
        this.leftCheckedKeys = this.leftData.filter(data => selectedKeys.indexOf(data.code) > -1).map(data => data.code)
        this.rightCheckedKeys = this.rightData.filter(data => selectedKeys.indexOf(data.code) > -1).map(data => data.code)
      }
    },
    // 移动到
    moveTo (direction) {
      const targetKeys = this.targetKeys
      const opposite = direction === 'left' ? 'right' : 'left'
      const moveKeys = this.getValidKeys(opposite)
      const newTargetKeys = direction === 'right' ? moveKeys.concat(targetKeys)
        : targetKeys.filter(targetKey => !moveKeys.some(checkedKey => targetKey === checkedKey))
      this.$refs[opposite].toggleSelectAll(false)
      /**
       * #event
       *
       * @name    change
       * @param   value        当前的值
       * @param   name         当前传入的props中的name
       * @param   direction    移动的方向
       * @param   moveKeys    当前移动的值
       * @description   值改变时触发事件
       * @body
       */
      this.$emit('change', newTargetKeys, this.name, direction, moveKeys)
    },
    handleLeftCheckedKeysChange (keys) {
      this.leftCheckedKeys = keys
    },
    handleRightCheckedKeysChange (keys) {
      this.rightCheckedKeys = keys
    },
    handleCheckedKeys () {
      const sourceSelectedKeys = this.getValidKeys('left')
      const targetSelectedKeys = this.getValidKeys('right')
      this.leftCheckedKeys = sourceSelectedKeys
      this.rightCheckedKeys = targetSelectedKeys
      /**
       * #event
       *
       * @name    selected
       * @param   sourceSelectedKeys        数据左边选中的值
       * @param   targetSelectedKeys        数据右边选中的值
       * @param   name         当前传入的props中的name
       * @description   选中时触发事件
       * @body
       */
      this.$emit('selected', sourceSelectedKeys, targetSelectedKeys, this.name)
    }
  },
  mounted () {
    this.splitData(true)
  }
}
